package concurrency

import (
	"cow_golang/shared_mod/logger"
	"fmt"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"
)

// typeQueues 对应多条不同的工作工作队列，key 可以是 玩家id，模块名称， 场景名称等唯一标识
type MultiWorkQueue struct {
	typeQueues sync.Map       // 任务队列集合
	queueChan  chan *JobQueue // 待处理队列通道
	maxWorkers int            // 最大工作协程数
	stopChan   chan struct{}  // 停止通道
	wg         sync.WaitGroup // 等待组
}

const (
	defaultQueueSize = 1024
)

func NewMultiWorkQueue(maxWorkers int) *MultiWorkQueue {
	p := &MultiWorkQueue{
		typeQueues: sync.Map{},
		queueChan:  make(chan *JobQueue, defaultQueueSize),
		maxWorkers: maxWorkers,
		stopChan:   make(chan struct{}),
	}

	p.wg.Add(maxWorkers)
	for i := 0; i < maxWorkers; i++ {
		go p.worker()
	}
	return p
}

// 停止多工作队列
func (p *MultiWorkQueue) Stop() {
	close(p.stopChan)
	p.wg.Wait()

	// 关闭所有队列
	p.typeQueues.Range(func(key, value interface{}) bool {
		if q, ok := value.(*JobQueue); ok {
			q.Close()
		}
		return true
	})
}

// 给指定的key对应的队列增加任务
func (p *MultiWorkQueue) AddTask(key string, job Job) {
	q, _ := p.typeQueues.LoadOrStore(key, NewQueue(defaultQueueSize))
	queue := q.(*JobQueue)

	if queue.Enqueue(job) {
		p.tryEnqueueQueue(queue)
	} else {
		// 处理队列满的情况
		fmt.Println("Queue is full, task dropped")
	}
}

// 将有任务需要处理的任务队列，加入到chan，激活work去处理
func (p *MultiWorkQueue) tryEnqueueQueue(q *JobQueue) {
	// 检查当前队列是否正在被处理中
	if atomic.LoadInt32(&q.processing) == 0 {
		select {
		case p.queueChan <- q:
			logger.GetInstance().Infof("tryEnqueueQueue acitve queue process queue job size:%d", q.Len())
		default:
			// 通道满时延迟重试
			time.AfterFunc(10*time.Millisecond, func() {
				p.tryEnqueueQueue(q)
			})
		}
	}
}

// 工作goroutine处理躯体的任务
func (p *MultiWorkQueue) worker() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("[WORKER PANIC] %v\n", r)
			p.wg.Done() // 确保等待组计数正确
		}
	}()

	defer p.wg.Done()

	for {
		select {
		case q := <-p.queueChan:
			if atomic.CompareAndSwapInt32(&q.processing, 0, 1) {
				p.processQueue(q)
				atomic.StoreInt32(&q.processing, 0)

				// 检查是否有剩余任务
				if q.Len() > 0 {
					p.tryEnqueueQueue(q)
				}
			}
		case <-p.stopChan:
			return
		}
	}
}

// 遍历任务队列，按照顺序需要处理任务
func (p *MultiWorkQueue) processQueue(q *JobQueue) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("[processQueue QUEUE PANIC] %v\n", r)
		}
	}()
	for {
		job, ok := q.Dequeue()
		if !ok {
			break
		}
		p.safeExec(job)
	}
}

// 调用job 的 exec 执行具体任务
func (p *MultiWorkQueue) safeExec(job Job) {
	defer func() {
		if r := recover(); r != nil {
			// 记录完整的堆栈信息
			stack := debug.Stack()
			logger.GetInstance().Fatalf("[PANIC RECOVERED] %v\n%s\n", r, stack)
		}
	}()

	// 执行前检查
	if job == nil {
		fmt.Println("[WARN] nil job skipped")
		return
	}

	start := time.Now()
	defer func() {
		logger.GetInstance().Debugf("Execution time: %v\n", time.Since(start))
	}()

	job.Execute()
}
